using FMOD;

using System;
using System.Collections.Generic;

namespace WindowsGame
{
  public class AudioEngine
  {
    private FMOD.System system = null;
    private Channel channel = null;

    private Dictionary<string, Sound> soundDictionary = new Dictionary<string, Sound>();

    private Sound music = null;
    private string currentMusicPath;
    private Channel musicChannel = null;

    public bool Initialize()
    {
      RESULT result;

      result = Factory.System_Create(ref system);
      ErrCheck(result);

      uint version = 0;

      result = system.getVersion(ref version);
      ErrCheck(result);

      if (version < VERSION.number)
      {
        throw new ApplicationException("Error! You are using an old version of FMOD " + version.ToString("X") + ". This program requires " + VERSION.number.ToString("X") + ".");
      }

      result = system.init(32, INITFLAG.NORMAL, (IntPtr)null);
      ErrCheck(result);

      return true;
    }

    private void ErrCheck(RESULT result)
    {
      if (result != RESULT.OK)
      {
        throw new ApplicationException("FMOD error! " + result + " - " + Error.String(result));
      }
    }

    public void LoadSound(string path)
    {
      Sound sound = null;
      RESULT result = system.createSound(path, MODE.DEFAULT, ref sound);
      ErrCheck(result);

      soundDictionary.Add(path, sound);
    }

    public void PlaySound(string path)
    {
      Sound sound;
      if (!soundDictionary.TryGetValue(path, out sound))
      {
        throw new ApplicationException("Sound " + sound + " not yet loaded. Use the AudioManager.LoadSound() method.");
      }
      else
      {
        RESULT result = system.playSound(CHANNELINDEX.FREE, sound, false, ref channel);
        ErrCheck(result);
      }
    }

    public void PlayMusic(string path)
    {
      bool isPlaying = false;
      RESULT result;

      if (musicChannel != null)
      {
        result = musicChannel.isPlaying(ref isPlaying);
      }
      else
      {
        isPlaying = false;
      }

      if (currentMusicPath == path && isPlaying)
      {
        return;
      }
      else if (currentMusicPath == path)
      {
        result = system.playSound(CHANNELINDEX.FREE, music, false, ref musicChannel);
        ErrCheck(result);
      }
      else
      {
        if (music != null)
        {
          result = music.release();
          ErrCheck(result);
        }

        result = system.createSound(path, MODE.SOFTWARE | MODE.CREATECOMPRESSEDSAMPLE | MODE.LOOP_NORMAL, ref music);
        ErrCheck(result);

        result = system.playSound(CHANNELINDEX.FREE, music, false, ref musicChannel);
        ErrCheck(result);

        currentMusicPath = path;
      }
    }

    public void StopMusic()
    {
      if (musicChannel != null)
      {
        RESULT result = musicChannel.stop();
        musicChannel = null;
        ErrCheck(result);
      }
    }

    public void SetVolume(float volume)
    {
      if (channel != null)
      {
        RESULT result = channel.setVolume(volume);
        ErrCheck(result);
      }
    }

    public void Update()
    {
      system.update();
    }

    public void Deinitialize()
    {
      Sound sound;
      foreach (KeyValuePair<string, Sound> kvp in soundDictionary)
      {
        soundDictionary.TryGetValue(kvp.Key, out sound);
        RESULT result = sound.release();
        ErrCheck(result);
      }
      soundDictionary.Clear();

      if (music != null)
      {
        music.release();
      }

      system.release();
    }
  }
}
